// Author	: damphat@gmail.com
// Created	: 01/12/2008

#pragma once
#include "vn/IOCommon.h"
#include "vn/Stream.h"
#include "vn/Math.hpp"
#include <string.h>


IO_BEGIN

class MemoryStream : public Stream {
private:
	const Buf8 *m_buf;
	StmLen		m_len;
	StmPos		m_pos;

public:
	MemoryStream(const Buf8 *buf, StmLen len)
		: m_buf(buf), m_len(len), m_pos(0) {
	}

	virtual StmLen Read(Buf8 *buf, StmLen len) {
		CHECK_ARG_BUFFER(buf, len);
		CHECK_STATUS(m_buf);
		StmLen remain = Math::Max(m_len - m_pos, 0);
		StmLen retsiz = Math::Min(len, remain);
		Mem::Copy(buf, m_buf + m_pos, retsiz);
		m_pos += retsiz;
		return retsiz;
	}

	virtual void Write(const Buf8 *buf,	StmLen len) {
		STREAM_NOT_SUPPORTED
	}

	virtual StmPos Seek(StmOff offset, SeekOrigin origin) {
		CHECK_STATUS(m_buf);
		switch (origin) {
			case SeekBegin:
				CHECK_ARG(offset >= 0);
				m_pos = offset;
				break;
			case SeekCurrent:
				CHECK_ARG(m_pos + offset >= 0);
				m_pos += offset;
				break;
			case SeekEnd:
				CHECK_ARG(m_len + offset >= 0);
				m_pos = m_len + offset;
				break;
		}

		return m_pos;
	}

	virtual void Flush()	{ }
	virtual void Close()	{ }

	virtual bool CanRead()  { return true; }
	virtual bool CanWrite() { return false; }
	virtual bool CanSeek()  { return true; }

	virtual StmPos GetPosition() {
		CHECK_STATUS(m_buf);
		return m_pos;
	}

	virtual void SetPosition(StmPos pos) {
		CHECK_ARG(pos >= 0);
		CHECK_STATUS(m_buf);
		m_pos = pos;
	}

	virtual StmLen GetLength() {
		CHECK_STATUS(m_buf);
		return m_len;
	}

	virtual void SetLength(StmLen len) {
		STREAM_NOT_SUPPORTED
	}

	virtual ~MemoryStream() {
	}
};

IO_END
